package org.budo.poi.util;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.budo.support.lang.util.IoUtil;
import org.budo.support.lang.util.MapUtil;
import org.budo.support.lang.util.NumberUtil;
import org.budo.support.lang.util.StringUtil;
import org.budo.support.servlet.util.ResponseUtil;
import org.budo.support.spring.expression.util.SpelUtil;

/**
 * @author lmw
 */
public class ExcelBuilder {
    private List<SheetBuilder> sheetBuilders = new ArrayList<SheetBuilder>();

    public SheetBuilder sheet(String sheetName) {
        SheetBuilder sheetBuilder = new SheetBuilder(sheetName, this);
        this.sheetBuilders.add(sheetBuilder);
        return sheetBuilder;
    }

    public Workbook toWorkbook() {
        Workbook workbook = new HSSFWorkbook();
        for (SheetBuilder sheetBuilder : this.sheetBuilders) {
            Sheet sheet = workbook.createSheet(sheetBuilder.name());
            this.writeHeader(sheet, sheetBuilder);

            if (null != sheetBuilder.list()) {
                this.writeData_list(sheet, sheetBuilder);
            } else {
                this.writeData_dataProducer(sheet, sheetBuilder);
            }
        }
        return workbook;
    }

    private void writeData_dataProducer(Sheet sheet, SheetBuilder sheetBuilder) {
        String[] headerNames = sheetBuilder.headerNames();

        DataProducer dataProducer = sheetBuilder.dataProducer();

        int k = 1;

        for (int i = 0; i < 999; i++) {
            List<?> list = dataProducer.produce(i);
            if (NumberUtil.equals(DataProducer.END.hashCode(), list.hashCode())) {
                break;
            }

            for (Object each : list) {
                Row row_i = sheet.createRow(k);
                for (int j = 0; j < headerNames.length; j++) {
                    Object valueTemplate = sheetBuilder.header().get(headerNames[j]);
                    Map<String, Object> map = MapUtil.stringObjectMap("_index", k, "_each", each);
                    String value = SpelUtil.merge((String) valueTemplate, map);
                    row_i.createCell(j).setCellValue(value);
                }

                k++;
            }
        }
    }

    private void writeData_list(Sheet sheet, SheetBuilder sheetBuilder) {
        List<?> list = sheetBuilder.list();
        String[] headerNames = sheetBuilder.headerNames();
        int i = 1;

        for (Object each : list) {
            Row row_i = sheet.createRow(i);
            for (int j = 0; j < headerNames.length; j++) {
                Object valueTemplate = sheetBuilder.header().get(headerNames[j]);
                Map<String, Object> map = MapUtil.stringObjectMap("_index", i, "_each", each);
                String value = SpelUtil.merge((String) valueTemplate, map);
                row_i.createCell(j).setCellValue(value);
            }

            i++;
        }
    }

    private String[] writeHeader(Sheet sheet, SheetBuilder sheetBuilder) {
        Row row_0 = sheet.createRow(0);
        String[] headers = sheetBuilder.headerNames();

        for (int i = 0; i < headers.length; i++) {
            row_0.createCell(i).setCellValue(headers[i]);
        }
        return headers;
    }

    public InputStream toInputStream() {
        Workbook workbook = this.toWorkbook();
        return WorkbookUtil.toInputStream(workbook);
    }

    public void download(HttpServletResponse response, String fileName) {
        response.reset(); // 清空输出流

        response.setContentType("application/msexcel"); // 定义输出类型
        response.setHeader("Content-disposition", "attachment; filename=" + StringUtil.gb2312_to_iso_8859_1(fileName) + ".xls"); // 文件名

        Workbook workbook = this.toWorkbook();
        OutputStream outputStream = ResponseUtil.getOutputStream(response); // 取得输出流
        WorkbookUtil.write(workbook, outputStream);

        IoUtil.close(outputStream); // 关闭流
    }

    public void toFile(File file) {
        Workbook workbook = this.toWorkbook();
        OutputStream outputStream = IoUtil.fileOutputStream(file);
        WorkbookUtil.write(workbook, outputStream);
    }
}